package com.wzdigit.wms.wms.service.order;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wzdigit.framework.Shift;
import com.wzdigit.wms.basic.client.request.downaway.SubmitDownAwayRequest;
import com.wzdigit.wms.basic.client.response.Result;
import com.wzdigit.wms.basic.client.response.basic.LocationResponse;
import com.wzdigit.wms.basic.domain.dtos.inventory.SnInforDto;
import com.wzdigit.wms.basic.domain.dtos.inventory.UpdateInventoryInputDto;
import com.wzdigit.wms.basic.domain.inventory.Goods;
import com.wzdigit.wms.basic.domain.inventory.GoodsLog;
import com.wzdigit.wms.basic.domain.inventory.InvTrans;
import com.wzdigit.wms.basic.enums.GoodsStatusEnum;
import com.wzdigit.wms.basic.enums.InvTransStatusEnum;
import com.wzdigit.wms.basic.enums.OpCodeEnum;
import com.wzdigit.wms.basic.enums.SnScanTypeEnum;
import com.wzdigit.wms.basic.mapper.core.basic.LocationMapper;
import com.wzdigit.wms.basic.util.HttpSessionUtil;
import com.wzdigit.wms.basic.util.StringUtils;
import com.wzdigit.wms.wms.service.core.GoodsService;
import com.wzdigit.wms.basic.service.code.InventoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DownAwayService {

	@Autowired
	private LocationMapper locationMapper;
	
    @Autowired
    private GoodsService goodsService;
    
    @Autowired
    private InventoryService inventoryService;

    private final Lock lock = new ReentrantLock();
    
    /**
     * 扫描sn
     *
     * @param sn
     * @param twScanMode
     * @return
     */
    public Result<List<SnInforDto>> scanSn(String sn, Integer twScanMode) {
		if (StringUtils.isNull(sn)) {
			Shift.fatal("请扫描sn!");
		}
		if (twScanMode != 0 && twScanMode != 1) {
			Shift.fatal("请输入正确的扫描方式!");
		}
        
        List<SnInforDto> snInfoList;
        if (twScanMode == 0) {
            //单台
            snInfoList = goodsService.selectSnInfosBySn(sn, SnScanTypeEnum.SELECT_SN);
        } else {
            //整板
            snInfoList = goodsService.selectSnInfosBySn(sn, SnScanTypeEnum.SELECT_PALLET);
        }
        if (snInfoList.size() == 0) {
        	Shift.fatal(String.format("该条码:%s不存在!", sn));
        }
        for (SnInforDto snInforDto : snInfoList) {
            if (snInforDto.getWhsId() == null) {
            	Shift.fatal(String.format("该条码:%s没有入库!", snInforDto.getGoodsSn()));
            }
            if (!snInforDto.getStatus().equals(GoodsStatusEnum.HAS_UP.getCode())) {
            	Shift.fatal(String.format("该条码:%s不是上架状态!", snInforDto.getGoodsSn()));
            }
            snInforDto.setTwScanMode(twScanMode);
        }
        return new Result<>(snInfoList);
    }

    /**
     * 提交
     *
     * @param input
     * @throws Exception 
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Result<String> submit(SubmitDownAwayRequest input, HttpServletRequest servletRequest) throws Exception {
    	lock.lock();
    	try {
    		String loginName = HttpSessionUtil.getLoginName(servletRequest);
        	
        	Integer twScanMode = input.getTwScanMode();
        	if (twScanMode != 0 && twScanMode != 1) {
    			Shift.fatal("请输入正确的扫描方式!");
    		}
        	
            // 获取goods 信息
        	List<String> snList = input.getSnList();
            List<Goods> goodsList = goodsService.selectListByListSn(snList);
            if (goodsList.size() < snList.size()) {
                List<String> existSn = goodsList.stream().map(Goods::getGoodsSn).distinct().collect(Collectors.toList());
                List<String> notExistSn = snList.stream().filter(t -> !existSn.contains(t)).collect(Collectors.toList());
                Shift.fatal("以下sn没有找不到信息:[" + String.join(",", notExistSn) + "]");
            }
            goodsList.forEach(sn -> {
                if (sn.getWhsId() == null) {
                	Shift.fatal(String.format("该条码:%s没有入库!", sn));
                }
                if (!sn.getStatus().equals(GoodsStatusEnum.HAS_UP.getCode())) {
                	Shift.fatal(String.format("该条码:%s不是上架状态!", sn));
                }
            });
            // 库存扣减
            handleInventory(goodsList, twScanMode, loginName);
            return new Result<>("下架成功!");
		} catch (Exception e) {
			throw e;
		} finally {
			lock.unlock();
		}
    }

    /**
     * 下架库存操作
     *
     * @param goodsList
     * @param twScanMode
     * @param userName
     * @throws Exception 
     */
    private void handleInventory(List<Goods> goodsList, Integer twScanMode, String userName) throws Exception {
    	Date date = new Date();
        Map<String, List<Goods>> goodsMap = goodsList.stream().collect(Collectors.groupingBy(g ->
        		g.getWhsId() + "#" + g.getLocId() + "#" + g.getOwner() + "#" + 
        		g.getSkuId() + "#" + g.getFactory() + "#" + g.getVendorId() + "#" + 
        		g.getLotno() + "#" + g.getInvAttr() + "#" + g.getQaStatus(), Collectors.toList()));
        for (String goodsKey : goodsMap.keySet()) {
        	goodsList = goodsMap.get(goodsKey);
            Goods firstGoods = goodsList.get(0);
            BigDecimal qty = goodsList.stream().map(Goods::getQty).reduce(BigDecimal.ZERO, BigDecimal::add);

            LocationResponse loc = locationMapper.selectOneByLocId(firstGoods.getLocId());
            
            UpdateInventoryInputDto fmInput = new UpdateInventoryInputDto();
            fmInput.setZoneId(loc.getZoneId());
            fmInput.setWhsId(firstGoods.getWhsId());
            fmInput.setLocId(firstGoods.getLocId());
            fmInput.setOwner(firstGoods.getOwner());
            fmInput.setSkuId(firstGoods.getSkuId());
            fmInput.setFactory(firstGoods.getFactory());
            fmInput.setVendorId(firstGoods.getVendorId());
            fmInput.setLotNo(firstGoods.getLotno());
            fmInput.setInvAttr(firstGoods.getInvAttr());
            fmInput.setQaStatus(firstGoods.getQaStatus());
            fmInput.setUnit(firstGoods.getUnit());
            fmInput.setQty(qty.negate());
            fmInput.setOperator(userName);

            UpdateInventoryInputDto toInput = new UpdateInventoryInputDto();
            toInput.setWhsId(firstGoods.getWhsId());
            toInput.setOwner(firstGoods.getOwner());
            toInput.setSkuId(firstGoods.getSkuId());
            toInput.setFactory(firstGoods.getFactory());
            toInput.setVendorId(firstGoods.getVendorId());
            toInput.setLotNo(firstGoods.getLotno());
            toInput.setInvAttr(firstGoods.getInvAttr());
            toInput.setQaStatus(firstGoods.getQaStatus());
            toInput.setUnit(firstGoods.getUnit());
            toInput.setQty(qty);
            toInput.setOperator(userName);

            InvTrans log = new InvTrans();
            log.setOpCode(OpCodeEnum.PUTOFF.getCode());
            log.setDocType("T08");
            log.setDocNo(" ");
            log.setDocLineNo(" ");
            log.setTrsnNo("");
            log.setTrsnLineNo("");
            log.setStatus(InvTransStatusEnum.FINISHED.getCode());
            log.setTransTime(date);
            log.setOperator(userName);
            log.setTransQty(qty);
            log.setCreateTime(date);
            log.setCreateUser(userName);

            inventoryService.inventoryTransfer(fmInput, toInput, log);

            //记录sn操作日志
            for (Goods goods : goodsList) {
            	 String oldGoodsJson = JSON.toJSONString(goods);		// 原先的json
            	 
                 if (twScanMode == 0) {
                     goods.setPkgId(null);								// 置空外包装
                 }
                 goods.setLocId(null);									// 置空库位
                 goods.setStatus(GoodsStatusEnum.WAIT_DOWM.getCode());	// 已下架
                 goods.setModifyUser(userName);
                 goods.setModifyTime(date);

                 // 更新外包装、库位、状态
                 goodsService.updateLocIdAndPkgIdAndStatusById(goods);	//	更新条码

                 String newGoodsJson = JSON.toJSONString(goods);        //	更新后的json
                 String jsonStr = "未更新的:" + oldGoodsJson + ",更新的:" + newGoodsJson;

                 GoodsLog goodsLog = new GoodsLog();
                 goodsLog.setInvTransId(log.getInvTransId());
                 goodsLog.setGoodsSn(goods.getGoodsSn());
                 goodsLog.setOpCode(OpCodeEnum.PUTOFF.getCode());
                 goodsLog.setOperator(userName);
                 goodsLog.setReason("货品下架");
                 goodsLog.setUpdateContent(jsonStr);
                 goodsLog.setOperator(userName);
                 goodsLog.setCreateUser(userName);
                 goodsLog.setCreateTime(date);
                 goodsService.insertGoodsLog(goodsLog);
			}
        }
    }

    /*private void updateGoods(Goods goods) {
        LambdaUpdateWrapper<Goods> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Goods::getGoodsId, goods.getGoodsId());
        updateWrapper.set(Goods::getStatus, goods.getStatus());
        if (goods.getLocId() == null) {
            updateWrapper.setSql("LOC_ID = NULL");
        } else {
            updateWrapper.set(Goods::getLocId, goods.getLocId());
        }
        if (goods.getPkgId() == null) {
            updateWrapper.setSql("PKG_ID = NULL");
        } else {
            updateWrapper.set(Goods::getPkgId, goods.getPkgId());
        }
        updateWrapper.set(Goods::getModifyTime, goods.getModifyTime());
        updateWrapper.set(Goods::getModifyUser, goods.getModifyUser());
        goodsService.getGoodsMapper().update(null, updateWrapper);
    }*/
}